﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.Network;
using System.Data.Common;
using System.Data;
using Rappelz.GameServer.Network.GameClient;


namespace Rappelz.GameServer.Database
{
    /// <summary>
    /// DBLoader_Monster (smp_read_character_list, smp_read_item_equip_info)
    /// </summary>
    public class DBLoader_Monster : IDBProc
    {
        GameDBManager db;
        private enum DBFields : int
        {
            AccountId = 0,
        }

        public DBLoader_Monster(GameDBManager dbManager)
        {
            db = dbManager;
        }

        BaseObject m_CBObject;

        public void SetCB(BaseObject obj)
        {
            m_CBObject = obj;
        }

        public void RunCB()
        {
            if (m_CBObject != null)
                m_CBObject.onEndQuery();
        }


        public bool onProcess()
        {
            DbConnection conn = db.CreateConnection();
            LoadMonsterData(conn);
            LoadSummonData(conn);
            //            LoadSummonLevelBonusData(conn);
            LoadDropGroupData(conn);
            LoadSummonNames(conn);
            return true;
        }

        private bool LoadMonsterData(DbConnection conn)
        {

            //LoadMonsterSkillData(conn);
            LoadMonsterItemDropData(conn);

            DbCommand cmd = conn.CreateCommand();

            cmd.CommandText = "Select * from MonsterResource";
            cmd.CommandType = CommandType.Text;
            int count = 0;
            conn.Open();
            try
            {
                DbDataReaderTypeCastHelper dr = new DbDataReaderTypeCastHelper(cmd.ExecuteReader());
                while (dr.Read())
                {
                    dbMonster monster = new dbMonster();
                    monster.trigger[0] = new MonsterBase.MonsterTrigger();
                    monster.trigger[1] = new MonsterBase.MonsterTrigger();
                    monster.trigger[2] = new MonsterBase.MonsterTrigger();
                    monster.trigger[3] = new MonsterBase.MonsterTrigger();
                    monster.trigger[4] = new MonsterBase.MonsterTrigger();
                    monster.trigger[5] = new MonsterBase.MonsterTrigger();
                    monster.skill_info[0] = new MonsterBase.MonsterSkillInfo();
                    monster.skill_info[1] = new MonsterBase.MonsterSkillInfo();
                    monster.skill_info[2] = new MonsterBase.MonsterSkillInfo();
                    monster.skill_info[3] = new MonsterBase.MonsterSkillInfo();
                    monster.skill_info[4] = new MonsterBase.MonsterSkillInfo();
                    monster.skill_info[5] = new MonsterBase.MonsterSkillInfo();

                    int off = 0;
                    monster.uid = dr.GetInt32(off++);
                    monster.monster_group = dr.GetInt32(off++);
                    monster.name_id = dr.GetInt32(off++);
                    monster.location_id = dr.GetInt32(off++);
                    string model = dr.GetString(off++);
                    int motion_file_id = dr.GetInt32(off++);
                    monster.transform_level = dr.GetInt32(off++);
                    monster.walk_type = dr.GetByte(off++);
                    int slant_type = dr.GetByte(off++);
                    monster.size = (float)dr.GetDecimal(off++);
                    monster.scale = (float)dr.GetDecimal(off++);
                    float target_fx_size = (float)dr.GetDecimal(off++);
                    int camera_x = dr.GetInt32(off++);
                    int camera_y = dr.GetInt32(off++);
                    int camera_z = dr.GetInt32(off++);
                    float target_x = (float)dr.GetDecimal(off++);
                    float target_y = (float)dr.GetDecimal(off++);
                    float target_z = (float)dr.GetDecimal(off++);
                    monster.level = dr.GetInt32(off++);
                    monster.monster_group = dr.GetInt32(off++); // grp
                    monster.magic_type = dr.GetInt32(off++);
                    monster.race = dr.GetInt32(off++);
                    monster.visible_range = dr.GetInt32(off++) * 12;
                    monster.chase_range = dr.GetInt32(off++);
                    monster.f_first_attack = dr.GetByte(off++);
                    monster.f_group_first_attack = dr.GetByte(off++);
                    monster.f_response_casting = dr.GetByte(off++);
                    monster.f_response_race = dr.GetByte(off++);
                    monster.f_response_battle = dr.GetByte(off++);
                    monster.monster_type = (int)dr.GetByte(off++);
                    monster.stat_id = dr.GetInt32(off++);
                    monster.fight_type = dr.GetInt32(off++);
                    int skill_link_id = dr.GetInt32(off++);
/*
                    for(int i = 0; i < 6; ++i)
                    {
                        monster.trigger[i].id = dr.GetInt32(off++);
                        monster.trigger[i].value[0] = (float)dr.GetDecimal(off++);
                        monster.trigger[i].value[1] = (float)dr.GetDecimal(off++);
                        monster.trigger[i].script = dr.GetString(off++);
                    }
*/
                    int material = dr.GetInt32(off++);
                    int weapon_type = dr.GetInt32(off++);
                    int attack_motion_speed = dr.GetInt32(off++);
                    monster.ability = dr.GetInt32(off++);
                    int standard_walk_speed = dr.GetInt32(off++);
                    int standard_run_spped = dr.GetInt32(off++);
                    monster.walk_speed = dr.GetInt32(off++);
                    monster.run_speed = dr.GetInt32(off++);
                    monster.attack_range = (int)(dr.GetDecimal(off++) * 100);
                    monster.hidesense_range = (int)(dr.GetDecimal(off++) * 12);
                    monster.hp = dr.GetInt32(off++);
                    monster.mp = dr.GetInt32(off++);
                    monster.attack_point = dr.GetInt32(off++);
                    monster.magic_point = dr.GetInt32(off++);
                    monster.defence = dr.GetInt32(off++);
                    monster.magic_defence = dr.GetInt32(off++);
                    monster.attack_speed = dr.GetInt32(off++);
                    monster.casting_speed = dr.GetInt32(off++);
                    monster.accuracy = dr.GetInt32(off++);
                    monster.avoid = dr.GetInt32(off++);
                    monster.magic_accuracy = dr.GetInt32(off++);
                    monster.magic_avoid = dr.GetInt32(off++);
                    monster.taming_code = dr.GetInt32(off++);
                    monster.taming_percentage = (float)dr.GetDecimal(off++);
                    monster.taming_exp_adjust = (float)dr.GetDecimal(off++);
                    monster.exp = dr.GetInt32(off++);
                    monster.jp = dr.GetInt32(off++);
                    monster.gold_drop_percentage = dr.GetInt32(off++);
                    monster.gold_min = dr.GetInt32(off++);
                    monster.gold_max = dr.GetInt32(off++);
                    monster.chaos_drop_percentage = dr.GetInt32(off++);
                    monster.chaos_min = dr.GetInt32(off++);
                    monster.chaos_max = dr.GetInt32(off++);
                    monster.exp_2 = dr.GetInt32(off++);
                    monster.jp_2 = dr.GetInt32(off++);
                    monster.gold_min_2 = dr.GetInt32(off++);
                    monster.gold_max_2 = dr.GetInt32(off++);
                    monster.chaos_min_2 = dr.GetInt32(off++);
                    monster.chaos_max_2 = dr.GetInt32(off++);
                    int drop_link_id = dr.GetInt32(off++);
/*
                    for(int i = 0; i < 10; ++i)
                    {
                        monster.drop_item_id[i] = dr.GetInt32(off++);
                        monster.drop_percentage[i] = (int)(float)(dr.GetDecimal(off++) * 100000000);
                        monster.drop_min_count[i] = dr.GetInt16(off++);
                        monster.drop_max_count[i] = dr.GetInt16(off++);
                        monster.drop_min_level[i] = dr.GetInt16(off++);
                        monster.drop_max_level[i] = dr.GetInt16(off++);
                    }
*/

/*
                    for(int i = 0; i < 6; ++i)
                    {
                        monster.skill_info[i].skill_id = dr.GetInt32(off++);
                        monster.skill_info[i].skill_lvl = dr.GetInt32(off++);
                        monster.skill_info[i].skill_probability = (float)dr.GetDecimal(off++);
                    }
*/
                    int texture_group = dr.GetInt32(off++);
                    monster.local_flag = dr.GetInt32(off++);

                    if ((GameRule.nCurrentLocalFlag & monster.local_flag) == 0)
                    {
                        monster.attack_type = 0;

                        if (monster.f_first_attack != 0)
                            monster.attack_type = 1;
                        if (monster.f_group_first_attack != 0)
                            monster.attack_type |= 2;
                        if (monster.f_response_casting != 0)
                            monster.attack_type |= 4;
                        if (monster.f_response_race != 0)
                            monster.attack_type |= 8;
                        if (monster.f_response_battle != 0)
                            monster.attack_type |= 0x10;

                        if (GameRule.bChangeMonsterDropSet)
                        {
                            monster.exp = monster.exp_2;
                            monster.jp = monster.jp_2;
                            monster.gold_min = monster.gold_min_2;
                            monster.gold_max = monster.gold_max_2;
                            monster.chaos_min = monster.chaos_min_2;
                            monster.chaos_max = monster.chaos_max_2;
                        }
                        monster.item_drop_list = GameContent.GetMonsterDropTable(drop_link_id);
                        GameContent.RegisterMonsterInfo(monster);
                        WorldLocationManager.Instance.RegisterMonsterLocation((uint)monster.location_id, (uint)monster.uid);
                        count++;
                    }
                }
            }
            catch (System.Data.SqlClient.SqlException e)
            {
                Globals.Log.Warning("Can't load MonsterResource database, Sql string: {0}", e.Message);
            }
            catch (Exception ex)
            {
                Globals.Log.Error("DBLoader_Monster.LoadMonsterData Exception: {0}", ex);
            }
            conn.Close();

            Globals.Log.Info("Total {0} Mobs loaded from MonsterResource", count);

            return true;
        }

        private bool LoadMonsterItemDropData(DbConnection conn)
        {
            DbCommand cmd = conn.CreateCommand();

            cmd.CommandText = "SELECT * FROM dbo.MonsterDropTableResource ORDER BY id, sub_id";
            cmd.CommandType = CommandType.Text;
            int count = 0;
            int nLastID = -1;
            List<MonsterBase.MonsterItemDropInfo> drops = new List<MonsterBase.MonsterItemDropInfo>();

            conn.Open();
            try
            {
                DbDataReaderTypeCastHelper dr = new DbDataReaderTypeCastHelper(cmd.ExecuteReader());
                while (dr.Read())
                {
                    int off = 0;

                    int nID = dr.GetInt32(off++);
                    int nSubID = dr.GetInt32(off++);

                    for (int i = 0; i < 10; ++i)
                    {
                        MonsterBase.MonsterItemDropInfo drop = new MonsterBase.MonsterItemDropInfo();
                        drop.item_id = dr.GetInt32(off++);
                        drop.percentage = (int)(float)(dr.GetDecimal(off++) * 100000000);
                        drop.min_count = dr.GetInt16(off++);
                        drop.max_count = dr.GetInt16(off++);
                        drop.min_level = dr.GetInt16(off++);
                        drop.max_level = dr.GetInt16(off++);
                        drops.Add(drop);
                    }

                    if(nLastID != -1 && nLastID != nID)
                    {
                        // register the drop here
                        GameContent.RegisterMonsterDropTable(nID, drops);
                        drops.Clear();
                    }
                    nLastID = nID;
                    count++;
                }
            }
            catch (Exception ex)
            {
                Globals.Log.Error("DBLoader_Monster.LoadMonsterItemDropData Exception: {0}", ex);
            }
            conn.Close();

            Globals.Log.Info("Total {0} MonsterDrops loaded from MonsterDropTableResource", count);

            return true;
        }

        private bool LoadDropGroupData(DbConnection conn)
        {

            DbCommand cmd = conn.CreateCommand();

            cmd.CommandText = "Select * from DropGroupResource";
            cmd.CommandType = CommandType.Text;
            int count = 0;
            conn.Open();
            try
            {
                DbDataReaderTypeCastHelper dr = new DbDataReaderTypeCastHelper(cmd.ExecuteReader());
                while (dr.Read())
                {
                    DropGroup dg = new DropGroup();

                    int off = 0;
                    dg.uid = dr.GetInt32(off++);

                    for(int i = 0; i < DropGroup.MAX_DROP_GROUP; ++i)
                    {
                        dg.drop_item_id[i] = dr.GetInt32(off++);
                        dg.drop_min_count[i] = (int)dr.GetInt64(off++);
                        dg.drop_max_count[i] = (int)dr.GetInt64(off++);
                        dg.drop_percentage[i] = (int)(float)(dr.GetDecimal(off++) * 100000000);
                    }

                    GameContent.RegisterDropGroupInfo(dg);
                    count++;
                }
            }
            catch (Exception ex)
            {
                Globals.Log.Error("DB_Loader_Monster.LoadDropGroupData Exception: {0}", ex);
            }
            conn.Close();

            Globals.Log.Info("Total {0} Mobs loaded from DropGroupResource", count);

            return true;
        }

        private bool LoadSummonData(DbConnection conn)
        {

            DbCommand cmd = conn.CreateCommand();

            cmd.CommandText = "Select * from SummonResource";
            cmd.CommandType = CommandType.Text;
            int count = 0;
            conn.Open();
            try
            {
                DbDataReaderTypeCastHelper dr = new DbDataReaderTypeCastHelper(cmd.ExecuteReader());
                while (dr.Read())
                {
                    int off = 0;
                    SummonBase sb = new SummonBase();

                    sb.uid = dr.GetInt32(off++);
                    int model_id = dr.GetInt32(off++);
                    sb.name_id = dr.GetInt32(off++);
                    sb.type = dr.GetInt32(off++);
                    sb.magic_type = dr.GetInt32(off++);
                    sb.rate = (sbyte)dr.GetByte(off++);
                    sb.stat_id = dr.GetInt32(off++);
                    sb.size = (float)dr.GetDecimal(off++);
                    sb.scale = (float)dr.GetDecimal(off++);
                    float target_fx_size = (float)dr.GetDecimal(off++);
                    int standard_walk_speed = dr.GetInt32(off++);
                    int standard_run_speed = dr.GetInt32(off++);
                    sb.riding_speed = dr.GetInt32(off++);
                    sb.run_speed = dr.GetInt32(off++);
                    sb.is_riding_only = (sbyte)dr.GetByte(off++);
                    int riding_motion_type = dr.GetInt32(off++);
                    sb.attack_range = (int)((float)dr.GetDecimal(off++)*100);
                    int walk_type = dr.GetInt32(off++);
                    int slant_type = dr.GetInt32(off++);
                    int material = dr.GetInt32(off++);
                    int weapon_type = dr.GetInt32(off++);
                    int attack_motion_speed = dr.GetInt32(off++);
                    sb.evolve_type = dr.GetInt32(off++); // form ?
                    sb.evolve_target = dr.GetInt32(off++);
                    int camera_x = dr.GetInt32(off++);
                    int camera_y = dr.GetInt32(off++);
                    int camera_z = dr.GetInt32(off++);
                    float target_x = (float)dr.GetDecimal(off++);
                    float target_y = (float)dr.GetDecimal(off++);
                    float target_z = (float)dr.GetDecimal(off++);
                    string model = dr.GetString(off++);
                    int motion_file_id = dr.GetInt32(off++);
                    int face_id = dr.GetInt32(off++);
                    string face_file_name = dr.GetString(off++);
                    sb.card_id = dr.GetInt32(off++);
                    sb.strScript = dr.GetString(off++);

                    GameContent.RegisterSummonInfo(sb);
                    count++;
                }
            }
            catch (Exception ex)
            {
                Globals.Log.Error("DB_Loader_Monster.LoadSummonData Exception: {0}", ex);
            }
            conn.Close();

            Globals.Log.Info("Total {0} Summons loaded from SummonResource", count);

            return true;
        }

        private bool LoadSummonNames(DbConnection conn)
        {
            int sid;
            int is_post_fix;
            int text_id;
            int off;

            DbCommand cmd = conn.CreateCommand();

            cmd.CommandText = "Select * from SummonDefaultNameResource";
            cmd.CommandType = CommandType.Text;
            int count = 0;
            conn.Open();
            try
            {
                DbDataReaderTypeCastHelper dr = new DbDataReaderTypeCastHelper(cmd.ExecuteReader());
                while (dr.Read())
                {
                    off = 0;
                    sid = dr.GetInt32(off++);
                    is_post_fix = dr.GetInt32(off++);
                    text_id = dr.GetInt32(off++);

                    GameContent.RegisterSummonDefaultName(text_id, is_post_fix == 0);
                    count++;
                }
            }
            catch (Exception ex)
            {
                Globals.Log.Error("DB_Loader_Monster.LoadSummonNames Exception: {0}", ex);
            }
            conn.Close();

            Globals.Log.Info("Total {0} DefaultSummonNames loaded from SummonDefaultNameResource", count);

            cmd = conn.CreateCommand();

            cmd.CommandText = "Select * from SummonUniqueNameResource";
            cmd.CommandType = CommandType.Text;
            count = 0;
            conn.Open();
            try
            {
                DbDataReaderTypeCastHelper dr = new DbDataReaderTypeCastHelper(cmd.ExecuteReader());
                while (dr.Read())
                {
                    off = 0;
                    sid = dr.GetInt32(off++);
                    int summon_type = dr.GetInt32(off++);
                    text_id = dr.GetInt32(off++);

                    GameContent.RegisterSummonUniqueName(summon_type, text_id);
                    count++;
                }
            }
            catch (Exception ex)
            {
                Globals.Log.Error("DB_Loader_Monster.LoadSummonNames Exception: {0}", ex);
            }
            conn.Close();

            Globals.Log.Info("Total {0} UniqueSummonNames loaded from SummonUniqueNameResource", count);

            return true;
        }

    }
}
